package com.citusdata.elven.linearRoad;

import com.citusdata.elven.linearRoad.FullPosition;
import java.lang.IllegalStateException;


// Helper class that keeps historical and position-related information about a
// vehicle.
class VehicleInformation {
  private static final int STOP_CRITERIA = 3;  // 3+1 = 4 consecutive stops
  private static final int TIME_NOT_INIT = -1;

  // This class implements a fail-fast synchronization policy. It keeps track of
  // the "update" time during a write, and if the client tries to read state for
  // some other time, it throws an exception. 
  private FullPosition prevPosition;
  private int          prevLane;
  private int          prevTime = TIME_NOT_INIT; // Starts uninitialized

  private int          tollAssessment;  // TollNotification for previous segment
  private boolean      changedSegments;
  private int          stopCount;
  private boolean      justMoved;

  protected static boolean travelLane(int lane) {
    return (lane > 0 && lane < 4);
  }

  // For any given position report, the client *must* ensure that the calls to
  // this function precede all other calls to this object.
  protected synchronized void recordLocation(int time, 
                                             FullPosition position, int lane) {
    justMoved = false;

    if (prevPosition == null) {
      prevPosition = position;
      prevLane = lane;
      changedSegments = true;
      return;
    }

    if (travelLane(lane) && prevPosition.equals(position) && prevLane == lane) { 
      stopCount++;
    } else {
      if (stopCount >= STOP_CRITERIA) {
        justMoved = true;
      }
      stopCount = 0;
    }
    
    changedSegments = !(prevPosition.sameSegment(position));

    // No need to deep copy "position" object; FullPosition is immutable.
    prevPosition = position;
    prevLane = lane;
    prevTime = time;
  }

  private synchronized void checkAccessTime(int time) {
    if (prevTime == TIME_NOT_INIT) {
      return;
    }

    if (prevTime != time) {
      throw new IllegalStateException("Write and read times: <" + prevTime +
                                      " and " + time + "> do not match");
    }
  }

  protected synchronized boolean justStopped(int time) {
    checkAccessTime(time);
    return (stopCount == STOP_CRITERIA);
  }

  protected synchronized boolean justMoved(int time) {
    checkAccessTime(time);
    return justMoved;
  }

  protected synchronized boolean changedSegments(int time) {
    checkAccessTime(time);
    return changedSegments;
  }

  protected synchronized int getTollAssessment(int time) {
    checkAccessTime(time);
    return tollAssessment;
  }

  protected synchronized void setTollAssessment(int time, int futureToll) {
    checkAccessTime(time);
    tollAssessment = futureToll;
  }
}
